package vertx.starter.rx.db;

import io.reactivex.Single;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.sql.ResultSet;
import io.vertx.reactivex.ext.jdbc.JDBCClient;
import io.vertx.reactivex.ext.sql.SQLClientHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 改造Rx
 */
public class DatabaseServiceImpl implements DatabaseService {

    private static final
    Logger LOGGER = LoggerFactory.getLogger(DatabaseServiceImpl.class);

    private final HashMap<SqlQuery, String> sqlQueries;
    private final JDBCClient dbClient;

    DatabaseServiceImpl(JDBCClient dbClient, HashMap<SqlQuery, String> sqlQueries, Handler<AsyncResult<DatabaseService>> readyHandler) {
        this.dbClient = dbClient;
        this.sqlQueries = sqlQueries;

        SQLClientHelper.usingConnectionSingle(this.dbClient, conn -> conn
                .rxExecute(sqlQueries.get(SqlQuery.CREATE_PAGES_TABLE))
                .andThen(Single.just(this)));
    }

    @Override
    public DatabaseService fetchAllPages(Handler<AsyncResult<JsonArray>> resultHandler) {
        String query = sqlQueries.get(SqlQuery.ALL_PAGES);
        JsonArray params = new JsonArray();
        Single<ResultSet> resultSet = dbClient.rxQueryWithParams(query, params);
        resultSet.doOnSuccess(ss -> {
            List<JsonObject> jsonObjects = ss.getResults().stream().map(v -> {
                JsonObject entity = new JsonObject();
                Integer id = v.getInteger(0);
                String name = v.getString(1);
                String content = v.getString(2);
                entity.put("id", id);
                entity.put("name", name);
                entity.put("content", content);
                return entity;
            }).collect(Collectors.toList());
            resultHandler.handle(Future.succeededFuture(new JsonArray(jsonObjects)));
        });
        resultSet.doOnError((res) -> {

                    LOGGER.error("Database query error", res.getCause());
                    resultHandler.handle(Future.failedFuture(res.getCause()));
                }
        );
        return this;
    }

    @Override
    public DatabaseService fetchPage(String name, Handler<AsyncResult<JsonObject>> resultHandler) {
        dbClient.queryWithParams(sqlQueries.get(SqlQuery.GET_PAGE), new JsonArray().add(name), fetch -> {
            if (fetch.succeeded()) {
                JsonObject response = new JsonObject();
                ResultSet resultSet = fetch.result();
                if (resultSet.getNumRows() == 0) {
                    response.put("found", false);
                } else {
                    JsonArray row = resultSet.getResults().get(0);
                    response.put("content", row.getString(1));
                }
                resultHandler.handle(Future.succeededFuture(response));
            } else {
                LOGGER.error("Database query error", fetch.cause());
                resultHandler.handle(Future.failedFuture(fetch.cause()));
            }
        });
        return this;
    }

    @Override
    public DatabaseService createPage(String name, String markdown, Handler<AsyncResult<Integer>> resultHandler) {
        JsonArray data = new JsonArray().add(name).add(markdown);
        dbClient.updateWithParams(sqlQueries.get(SqlQuery.CREATE_PAGE), data, res -> {
            if (res.succeeded()) {
                resultHandler.handle(Future.succeededFuture());
            } else {
                LOGGER.error("Database query error", res.cause());
                resultHandler.handle(Future.failedFuture(res.cause()));
            }
        });
        return this;
    }

    @Override
    public DatabaseService savePage(int id, String markdown, Handler<AsyncResult<Integer>> resultHandler) {
        JsonArray data = new JsonArray().add(markdown).add(id);
        dbClient.updateWithParams(sqlQueries.get(SqlQuery.SAVE_PAGE), data, res -> {
            if (res.succeeded()) {
                resultHandler.handle(Future.succeededFuture());
            } else {
                LOGGER.error("Database query error", res.cause());
                resultHandler.handle(Future.failedFuture(res.cause()));
            }
        });
        return this;
    }

    @Override
    public DatabaseService deletePage(String name, Handler<AsyncResult<Integer>> resultHandler) {
        JsonArray data = new JsonArray();
        if (name != null) data.add(name);
        String sql = name == null ? sqlQueries.get(SqlQuery.DELETE_ALL_PAGE) : sqlQueries.get(SqlQuery.DELETE_PAGE);
        dbClient.updateWithParams(sql, data, res -> {
            if (res.succeeded()) {
                resultHandler.handle(Future.succeededFuture());
            } else {
                LOGGER.error("Database query error", res.cause());
                resultHandler.handle(Future.failedFuture(res.cause()));
            }
        });
        return this;
    }
}
